<?php
/**
 * 
 * @todo description of this class
 * 
 * @author Alton Crossley <crossleyframework@nogahidebootstrap.com>
 * @package Crossley Framework
 *  
 * @copyright Copyright (c) 2003-2009, Nogaide BootStrap INC. All rights reserved.
 * @license BSD http://opensource.org/licenses/bsd-license.php
 * @version $Id:$
 * 
 */
/**
 * purpose: to construct the Standard Object Response for the Controller
 *
 * @author Alton Crossley
 * @package Crossley Framework
 * @version 0.3
 *
 */
class X_Broker_Response
{
    /**
     * signifies a JSON array is returned
     *
     */
    const ENCODE_JSON = 'json';
    /**
     * signifies a HTML string is returned
     *
     */
    const ENCODE_HTML = 'html';
    /**
     * signifies a complex type is returned
     *
     */
    const ENCODE_COMPLEX = 'x';
    /**
	 * Configuration XML file to load from
	 *
	 * @var string
	 */
	protected $_sConfigName = 'javascript';

	/**
	 * Configuration section of the XML file to load
	 *
	 * @var string
	 */
	protected $_sConfigSection = 'dependencie_groups';

	/**
	 * 	Does this Response have any errors?
	 * 	@var boolean
	 */
	private $_bHasError = false;

	/**
	 * 	What are the global error messages?
	 * 	These are *not* validation errors,
	 * 	but more general errors.
	 * 	@var array
	 */
	private $_aErrorMessages = array();

	/**
	 * 	The result 'data'
	 *
	 * 	@var array
	 */
	private $_aData = array();

	/**
	 * 	HTML markup/output, if any
	 *
	 * 	@var string
	 */
	private $_sHTML = '';

	/**
	 * JS and CSS external file dependencies
	 *
	 * @example array('js' => array('js/foo.js', js/foo2.js), 'css' => array('style/foo.css'));
	 *
	 * @var array 2D
	 */
	private $_aDependencies = array('aJS' => array(), 'aCSS' => array());

	/**
	 * 	Bus messages (this is Alton's thing)
	 * 	@var array
	 */
	private $_aBusMessages = array();

	/**
	 * 	Add a global error message
	 *
	 * 	@param string $sError
	 */
	public function addError($sError)
	{
		$this->_aErrorMessages[] = $sError;
		$this->_bHasError = true;
	}

	/**
	 * Set all errors as an array
	 *
	 * @param array $aErrors
	 */
	public function setErrors(array $aErrors)
	{
	    $this->_aErrorMessages = $aErrors;
	    if (!empty($aErrors))
	    {
	        $this->_bHasError = true;
	    }
	}

	/**
	 * check to see if there are errors in the response
	 *
	 * @return bool
	 */
	public function hasErrors()
	{
	    return (bool)$this->_bHasError;
	}

	/**
	 * 	Remove errors
	 *
	 */
	public function removeErrors()
	{
		$this->_aErrorMessages = array();
		$this->_bHasError = false;
	}

	/**
	 * retrieve error messages array
	 *
	 * @return array
	 */
	public function getErrors()
	{
	    return $this->_aErrorMessages;
	}

	/**
	 * 	Add any kind of data *by key*
	 * 	(aForm and aValidationErrors are reserved)
	 *
	 * 	@param string $sKey
	 * 	@param mixed $mValue
	 */
	public function addData($sKey, $mValue)
	{
		if ($sKey != 'aForm' && $sKey != 'aValidationErrors')
		// form data and validation errors set on their own methods
		{
			$this->_aData[$sKey] = $mValue;
		}
	}

	/**
	 * 	Add form data (field/value)
	 *
	 * 	@param array $aFormData
	 */
	public function addFormData(array $aFormData, $bMerge = false)
	{
		if (array_key_exists('aForm', $this->_aData) && $bMerge)
		{
			$this->_aData['aForm'] = array_merge($this->_aData['aForm'], $aFormData);
		}
		else
		{
			$this->_aData['aForm'] = $aFormData;
		}
	}

	public function getFormData()
	{
		return (array_key_exists('aForm', $this->_aData) ? $this->_aData['aForm'] : array());
	}

	public function setHtml($sHtml)
	{
		$this->_sHTML = $sHtml;
	}

	/**
	 * 	Add validation errors
	 * 	(error messages keyed by dom id)
	 *
	 * 	@param array $aValidationErrors
	 */
	public function addValidationErrors(array $aValidationErrors)
	{
		$this->_aData['aValidationErrors'] = $aValidationErrors;
	}

	/**
	 * 	Does this reponse have validation errors?
	 *
	 * 	@return boolean
	 */
	public function hasValidationErrors()
	{
		return (array_key_exists('aValidationErrors', $this->_aData) && !empty($this->_aData['aValidationErrors']));
	}

	/**
	 * 	Get the standard array
	 * 	This is the main benefit here -- easy encapsulation
	 * 	of a complex array:
	 *
	 *     bHasError - simply a boolean indicating if errors were encountered
	 *         in processing
	 *     aErrorMessages - array of strings that are the actual errors encountered
	 *     aResult - the actual result of the request
	 *         [sHTML] - the html string built in the request.  Not always populated
	 *         [aData] - JSON object result of the request. Not always populated
	 *     aBusMessages - array of JSON bus message objects which are published
	 *         onto the event bus
	 *     aDependencies - array of string urls of dependencies
	 *         [js] = array of javascript urls
	 *         [css] = array of css urls
	 *
	 * 	@return array
	 */
	public function getArray()
	{
		return array(
			'bHasError' => $this->_bHasError,
			'aErrorMessages' => $this->_aErrorMessages,
			'aResult' => array(
				'aData' => $this->_aData,
				'sHTML' => $this->_sHTML
			),
			'aBusMessages' => $this->_aBusMessages,
			'aDependencies' => $this->_aDependencies
		);
	}

	/**
	 * direct access to the result data
	 * this overwrites any data currently in place
	 *
	 * @param unknown_type $xData
	 */
	public function setData($xData)
	{
	    $this->_aData = $xData;
	}

	/**
	 * add a js url to the dependency list
	 *
	 * @param stirng $sURL
	 */
	public function addJavaScriptDependency($xURL)
	{
	    if (is_string($xURL))
	    {
	        if (array_search($xURL, $this->_aDependencies['aJS']) === false)
	        {
	            array_push($this->_aDependencies['aJS'], trim($xURL));
	        }
	    }
	    elseif(is_array($xURL))
	    {
	        foreach ($xURL as $sUrl)
	        {
	            $this->addJavaScriptDependency((string)$sUrl);
	        }
	    }
	    else
	    {
	        $this->addJavaScriptDependency((string)$xURL);
	    }

	}

	public function setJavaScriptGroup($sGroupName, $bLoadChildren = 3)
	{
	    static $aLoaded = array();

	    if (array_search($sGroupName, $aLoaded))
	    {
	        return true;
	    }

	    array_push($aLoaded, $sGroupName);

        if (array_key_exists($sGroupName, $this->aConfig))
        {
            if (array_key_exists('children', $this->aConfig[$sGroupName]) && $bLoadChildren)
            {
                foreach (explode(',', $this->aConfig[$sGroupName]['children']) as $sChildKey)
                {
                    $this->setJavaScriptGroup(trim($sChildKey), ($bLoadChildren-1));
                }
            }

            if (array_key_exists('urls', $this->aConfig[$sGroupName]))
            {
                $this->addJavaScriptDependency(explode(',', $this->aConfig[$sGroupName]['urls']));
            }
        }
        else
        {
            trigger_error("'<strong>{$sGroupName}</strong>' does not exist in {$this->_sConfigName}.xml", E_USER_NOTICE);
        }

	}

	/**
	 * add a css url to the dependency list
	 *
	 * @param string $sURL
	 */
	public function addCSSDependency($sURL)
	{
	    array_push($this->_aDependencies['aCSS'], $sURL);
	}

	/**
	 * overwrite the dependency array
	 *
	 * @param array $aDependencies
	 */
	public function setDependencies(Array $aDependencies)
	{
	    if (!array_key_exists('aJS', $aDependencies) ||
	           !array_key_exists('aCSS', $aDependencies))
       {
           trigger_error('dependency array set to incomplete array structure ("aJS" or "aCSS" keys missing)', E_USER_NOTICE);
       }

	    $this->_aDependencies = $aDependencies;
	}

	/**
	 * gather dependencies in their respective rendered strings
	 *
	 * @return string
	 */
	public function getDependencyString()
	{
	    $sReturn = '';
	    foreach ($this->_aDependencies['aJS'] as $sJsUrl)
	    {
	        $oScript = new X_HTML_Script($sJsUrl);
	        $sReturn .= (string)$oScript;
	    }

	    foreach ($this->_aDependencies['aCSS'] as $sCssUrl)
	    {
	        $oLink = new X_HTML_Link_Stylesheet($sCssUrl);
	        $sReturn .= (string)$oLink;
	    }

	    return $sReturn;
	}

	/**
	 * standard toString returns JSON array
	 *
	 * @return srting
	 */
	function __toString()
	{
	    return json_encode($this->getArray());
	}
}